1 بارگذاری دادهها و کتابخانههای مورد نیاز
1.1 بارگذاری کتابخانههای R
اولین قدم، بارگذاری کتابخانههای لازم و بررسی اولیه دادهها برای درک ساختار، کیفیت و ویژگیهای آماری آن است.
library(caret)
library(dplyr)
library(skimr)
library(rpart)
library(rpart.plot)
library(randomForest)
library(ggplot2)
library(patchwork)
library(forcats)
library(DT)
نقش هر کتابخانه در این پروژه:
ما از dplyr و ggplot2 به عنوان ابزارهای
اصلی برای آمادهسازی و نمایش دادهها استفاده میکنیم. در قلب فرآیند یادگیری
ماشین، کتابخانه caret قرار دارد که وظیفه تقسیم دادهها و
مدیریت آموزش مدل را بر عهده دارد.
1.2 بارگذاری دیتاست
تشریح نحوه بارگذاری:
دستور read.csv
تابع اصلی R برای خواندن فایلهای متنی با جداکننده کاما است. استفاده از
تابع file.choose() در داخل آن، یک پنجره محاورهای باز میکند
تا شما بتوانید فایل را به صورت تعاملی از سیستم خود انتخاب کنید.
همچنین آرگومان header = TRUE به برنامه اعلام میکند که
سطر اول فایل شامل نام ستونها (Variables) است و نباید به
عنوان داده محاسباتی در نظر گرفته شود.
2 پیشپردازش دادهها
2.1 آمار توصیفی
## 'data.frame': 397 obs. of 7 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ rank : chr "Prof" "Prof" "AsstProf" "Prof" ...
## $ discipline : chr "B" "B" "B" "B" ...
## $ yrs.since.phd: int 19 20 4 45 40 6 30 45 21 18 ...
## $ yrs.service : int 18 16 3 39 41 6 23 45 20 18 ...
## $ sex : chr "Male" "Male" "Male" "Male" ...
## $ salary : int 139750 173200 79750 115000 NA 97000 175000 147765 119250 129000 ...
## X rank discipline yrs.since.phd
## Min. : 1 Length:397 Length:397 Min. : 1.00
## 1st Qu.:100 Class :character Class :character 1st Qu.:12.00
## Median :199 Mode :character Mode :character Median :21.00
## Mean :199 Mean :22.32
## 3rd Qu.:298 3rd Qu.:32.00
## Max. :397 Max. :56.00
## NA's :3
## yrs.service sex salary
## Min. : 0.00 Length:397 Min. : 57800
## 1st Qu.: 7.00 Class :character 1st Qu.: 91000
## Median :16.00 Mode :character Median :107200
## Mean :17.56 Mean :113698
## 3rd Qu.:26.25 3rd Qu.:134368
## Max. :60.00 Max. :231545
## NA's :5 NA's :6
| Name | mis |
| Number of rows | 397 |
| Number of columns | 7 |
| _______________________ | |
| Column type frequency: | |
| character | 3 |
| numeric | 4 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| rank | 3 | 0.99 | 4 | 9 | 0 | 3 | 0 |
| discipline | 10 | 0.97 | 1 | 1 | 0 | 2 | 0 |
| sex | 5 | 0.99 | 4 | 6 | 0 | 2 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| X | 0 | 1.00 | 199.00 | 114.75 | 1 | 100 | 199 | 298.00 | 397 | ▇▇▇▇▇ |
| yrs.since.phd | 3 | 0.99 | 22.32 | 12.93 | 1 | 12 | 21 | 32.00 | 56 | ▇▇▆▅▁ |
| yrs.service | 5 | 0.99 | 17.56 | 12.91 | 0 | 7 | 16 | 26.25 | 60 | ▇▅▃▂▁ |
| salary | 6 | 0.98 | 113698.21 | 30425.73 | 57800 | 91000 | 107200 | 134367.50 | 231545 | ▆▇▅▂▁ |
datatable(head(mis, 100),
options = list(
scrollX = TRUE,
pageLength = 5,
dom = 'Bfrtip',
language = list(url = '//cdn.datatables.net/plug-ins/1.10.11/i18n/Persian.json')
),
caption = "جدول ۱: نمای کلی دیتاست اعضای هیئت علمی",
rownames = FALSE,
class = 'cell-border stripe hover'
)یافتههای حاصل از بررسی ساختار دادهها:
-
دستور
str(mis): ابعاد دقیق دادهها (۳۹۷ مشاهده و ۷ متغیر) و نوع دادهها (مانند Integer برای اعداد و Factor برای دستهها) را مشخص کرد. -
دستور
summary(mis): آمارههای توصیفی کلیدی شامل میانگین، میانه، کمینه/بیشینه و چارکها را محاسبه کرد که دید خوبی از توزیع متغیرهای عددی میدهد. -
دستور
skim(mis): این تابع قدرتمند، علاوه بر آمارهای پایه، وضعیت دادههای گمشده (Missing Values) را به تفکیک هر ستون گزارش داد. -
اقدام اصلاحی
mis$X <- NULL: ستون X که صرفاً یک شمارنده ردیف (Index) وارد شده از فایل CSV بود و ارزش تحلیلی برای مدلسازی نداشت، از دیتاست حذف گردید.
2.2 مصورسازی دادهها
مصورسازی به ما کمک میکند تا الگوها، روابط، مقادیر پرت و توزیع دادهها را بهتر درک کنیم.
par(mfrow = c(1, 4))
boxplot(mis$yrs.since.phd)
boxplot(mis$yrs.service)
boxplot(mis$salary)
boxplot(mis$salary ~ mis$rank)par(mfrow = c(1, 3))
barplot(table(mis$rank))
barplot(table(mis$discipline))
barplot(table(mis$sex))
تحلیل الگوهای بصری و آماری:
بررسی نمودارها حقایق
مهمی را درباره ساختار دادهها آشکار کرد:
- عدم توازن (Imbalance): دادهها در متغیرهای دستهای سوگیری دارند؛ به طوری که اکثریت نمونهها را رتبه «استاد تمام» (Prof) و جنسیت «مرد» تشکیل میدهند.
-
همبستگی کلیدی: نمودار جعبهای
salary ~ rankیک رابطه مستقیم و بسیار قوی را نشان میدهد. با ارتقای رتبه، میانه حقوق جهش قابل توجهی دارد؛ این ویژگی،salaryرا به یک پیشبینیکننده قدرتمند برای مدل تبدیل میکند. -
توزیع متغیرهای عددی:
-
متغیر
yrs.since.phd: توزیعی نسبتاً متقارن (شبهنرمال) دارد و اوج تراکم دادهها در بازه ۱۵ تا ۲۵ سال است. -
متغیر
yrs.service: دارای چولگی به راست (Right-skewed) است، به این معنی که اکثر اساتید سابقه خدمت کمتر از ۲۵ سال دارند. -
متغیر
salary: چولگی شدید به راست دارد. تمرکز اصلی حقوقها در بازه ۹۰ تا ۱۱۰ هزار دلار است و وجود دادههای پرت (Outliers) در حقوقهای بالا کاملاً مشهود است.
-
متغیر
2.3 پاکسازی دادهها
استراتژی مدیریت دادههای گمشده (Missing Values):
تحلیلها نشان میدهد حدود ۱۵٪ از دادهها در متغیرهای salary و
discipline مفقود هستند. در این مرحله تصمیمگیری به شرح زیر
انجام شد:
-
قابلیت مدل: اگرچه مدلهای درختی (مانند
rpart) میتوانند با استفاده از تکنیک «Surrogate Splits» مقادیر گمشده را مدیریت کنند، ما از این قابلیت صرفنظر کردیم. - رویکرد انتخابی: ما روش حذف کامل ردیف (Listwise Deletion) را انتخاب کردیم.
-
استدلال و ریسک: دلیل اصلی این انتخاب، سادهسازی تحلیل و
سازگاری با توابع ارزیابی استاندارد مانند
caret::confusionMatrixاست که با مقادیر NA دچار خطا میشوند.
هشدار: باید آگاه باشیم که این روش در صورتی که دادهها به طور تصادفی گم نشده باشند، میتواند باعث ایجاد اریبی (Bias) در نتایج نهایی شود.
mis <- mis %>% mutate(rank = as.factor(rank),discipline = as.factor(discipline),sex = as.factor(sex)) %>% na.omit() گامهای اجرایی پیشپردازش (Preprocessing Steps):
-
تبدیل نوع داده (Feature Encoding): با استفاده از دستور
mutate، ستونهای متنی (rank,discipline,sex) به ساختار Factor تبدیل شدند. این تبدیل برای R ضروری است تا بتواند سطوح (Levels) مختلف متغیرهای کیفی را در مدلسازی لحاظ کند. -
پاکسازی دادهها (Data Cleaning): با دستور
na.omit، استراتژی حذف کامل اعمال شد. این تابع کل دیتافریم را اسکن کرده و هر ردیفی را که حاوی حتی یک مقدار گمشده (NA) باشد، حذف میکند.
2.4 استدلالهای فنی در مدیریت دادهها
2.4.1 ۱. مدیریت دادههای پرت (Outliers Handling)
- مشاهده: نمودارهای جعبهای وجود مقادیر پرت در
متغیرهای
salaryوyrs.serviceرا نشان دادند. - تحلیل فنی: مدلهای مبتنی بر درخت (مانند CART) ذاتاً نسبت به دادههای پرت مقاوم (Robust) هستند. مکانیزم درخت بر اساس “آستانههای تقسیم” (Splitting Thresholds) کار میکند، نه میانگین یا واریانس. بنابراین، یک داده پرت (مثلاً حقوق بسیار بالا) صرفاً در یک سمتِ شرط قرار میگیرد و ساختار کلی مدل را منحرف نمیکند.
- اقدام نهایی: دادههای پرت حفظ شدند و تغییری در آنها ایجاد نشد.
2.4.2 ۲. مقیاسبندی ویژگیها (Feature Scaling)
- تحلیل فنی: استانداردسازی (Standardization) یا نرمالسازی (Normalization) برای مدلهایی که بر اساس “فاصله اقلیدسی” کار میکنند (مانند KNN، SVM یا رگرسیون لجستیک) حیاتی است. اما در مدلهای درختی، مقیاس اعداد تأثیری بر “خلوص گرهها” (Gini Impurity) یا انتخاب بهترین نقطه برش ندارد.
- اقدام نهایی: از آنجا که برای درخت تصمیم غیرضروری است، این مرحله نادیده گرفته شد (Skipped). ## ساخت مدل پیشبینی
2.5 تقسیم داده به مجموعه آموزشی و آزمایشی
set.seed(38712)
index <- createDataPartition(mis$rank, p = 0.75, list = FALSE)
train <- mis[index, ]
test <- mis[-index, ]
dim(train)## [1] 275 6
## [1] 90 6
تشریح فرآیند تقسیمبندی دادهها (Data Splitting):
-
تکرارپذیری (Reproducibility): دستور
set.seedتضمین میکند که اعداد تصادفی تولید شده در هر بار اجرای کد، یکسان باشند. این کار برای استناد به نتایج علمی ضروری است. -
نمونهگیری طبقهای (Stratified Sampling): تابع
createDataPartitionبه جای انتخاب تصادفی ساده، نسبت توزیع متغیر هدف (Rank) را در هر دو دسته حفظ میکند. یعنی اگر ۱۰٪ دادهها “دانشیار” هستند، در دادههای آموزشی و آزمایشی نیز همین ۱۰٪ حفظ میشود. - نسبت تقسیم: دادهها به دو بخش آموزشی (۷۵٪) برای ساخت مدل و آزمایشی (۲۵٪) برای سنجش نهایی تقسیم شدند.
2.6 پیادهسازی الگوریتم درخت تصمیم (CART)
در این مرحله، ما از الگوریتم rpart (Recursive Partitioning and Regression Trees) برای ساخت مدل طبقهبندی استفاده میکنیم. هدف این است که قوانینی استخراج کنیم که بتوانند بر اساس ویژگیهای موجود، رتبه علمی (Rank) را پیشبینی کنند.
تنظیمات ساخت مدل (Model Specification):
-
فرمول
rank ~ .: این نحوه نوشتار در R به مدل میگوید کهrankمتغیر هدف (Target) است و نقطه (.) به معنی “تمام ستونهای دیگر موجود در دیتاست” به عنوان متغیرهای پیشبینیکننده (Predictors) است. -
آرگومان
method = “class”: از آنجا که متغیر هدف ما کیفی (Categorical) است، این پارامتر به الگوریتم دستور میدهد که درخت را به صورت طبقهبندی (Classification) بسازد و نه رگرسیون. -
دادهها: مدل صرفاً روی دادههای
trainآموزش میبیند تا بعداً بتوانیم آن را با دادههایtestمحک بزنیم.
## Call:
## rpart(formula = rank ~ ., data = train, method = "class")
## n= 275
##
## CP nsplit rel error xerror xstd
## 1 0.48387097 0 1.0000000 1.000000 0.08435831
## 2 0.20430108 1 0.5161290 0.516129 0.06768372
## 3 0.05376344 2 0.3118280 0.311828 0.05476679
## 4 0.01000000 3 0.2580645 0.311828 0.05476679
##
## Variable importance
## yrs.since.phd yrs.service salary
## 42 33 25
##
## Node number 1: 275 observations, complexity param=0.483871
## predicted class=Prof expected loss=0.3381818 P(node) =1
## class counts: 47 46 182
## probabilities: 0.171 0.167 0.662
## left son=2 (69 obs) right son=3 (206 obs)
## Primary splits:
## yrs.since.phd < 11.5 to the left, improve=63.585430, (0 missing)
## yrs.service < 5.5 to the left, improve=47.413630, (0 missing)
## salary < 92850 to the left, improve=43.301910, (0 missing)
## sex splits as LR, improve= 3.398741, (0 missing)
## discipline splits as RL, improve= 1.274892, (0 missing)
## Surrogate splits:
## yrs.service < 5.5 to the left, agree=0.887, adj=0.551, (0 split)
## salary < 92025 to the left, agree=0.836, adj=0.348, (0 split)
##
## Node number 2: 69 observations, complexity param=0.2043011
## predicted class=AsstProf expected loss=0.3333333 P(node) =0.2509091
## class counts: 22 46 1
## probabilities: 0.319 0.667 0.014
## left son=4 (22 obs) right son=5 (47 obs)
## Primary splits:
## yrs.service < 5.5 to the right, improve=23.74729000, (0 missing)
## salary < 94054 to the right, improve=14.09444000, (0 missing)
## yrs.since.phd < 8.5 to the right, improve=14.07374000, (0 missing)
## sex splits as RL, improve= 0.37553430, (0 missing)
## discipline splits as RL, improve= 0.09879227, (0 missing)
## Surrogate splits:
## yrs.since.phd < 8.5 to the right, agree=0.855, adj=0.545, (0 split)
## salary < 94054 to the right, agree=0.855, adj=0.545, (0 split)
##
## Node number 3: 206 observations, complexity param=0.05376344
## predicted class=Prof expected loss=0.1213592 P(node) =0.7490909
## class counts: 25 0 181
## probabilities: 0.121 0.000 0.879
## left son=6 (17 obs) right son=7 (189 obs)
## Primary splits:
## salary < 87025 to the left, improve=10.24141000, (0 missing)
## yrs.since.phd < 13.5 to the left, improve= 6.35139400, (0 missing)
## yrs.service < 10.5 to the left, improve= 3.23197000, (0 missing)
## sex splits as LR, improve= 2.82329200, (0 missing)
## discipline splits as RL, improve= 0.07381862, (0 missing)
## Surrogate splits:
## yrs.since.phd < 48.5 to the right, agree=0.927, adj=0.118, (0 split)
## yrs.service < 48.5 to the right, agree=0.927, adj=0.118, (0 split)
##
## Node number 4: 22 observations
## predicted class=AssocProf expected loss=0.09090909 P(node) =0.08
## class counts: 20 1 1
## probabilities: 0.909 0.045 0.045
##
## Node number 5: 47 observations
## predicted class=AsstProf expected loss=0.04255319 P(node) =0.1709091
## class counts: 2 45 0
## probabilities: 0.043 0.957 0.000
##
## Node number 6: 17 observations
## predicted class=AssocProf expected loss=0.3529412 P(node) =0.06181818
## class counts: 11 0 6
## probabilities: 0.647 0.000 0.353
##
## Node number 7: 189 observations
## predicted class=Prof expected loss=0.07407407 P(node) =0.6872727
## class counts: 14 0 175
## probabilities: 0.074 0.000 0.926
# مدل بدون هرس
model1 <- rpart(rank ~ ., data = train, method = "class",
control = rpart.control(minsplit = 5, cp = 0))
rpart.plot(model1)تحلیل خروجی مدل اولیه (Unpruned Tree):
-
اهمیت متغیرها (Variable Importance): نتایج نشان میدهد
که دو متغیر
yrs.since.phd(سالهای پس از دکترا) وyrs.service(سابقه خدمت) با فاصله زیاد، تأثیرگذارترین عوامل در پیشبینی رتبه هستند. جالب اینجاست که متغیرsex(جنسیت) هیچ نقشی در این مدل نداشته است. -
تشخیص بیشبرازش (Overfitting Diagnosis): با بررسی جدول
CP (Complexity Parameter)، مشاهده میشود که خطای اعتبارسنجی متقابل
(
xerror) در ابتدا کاهش مییابد و در ۴ تقسیم (nsplit=4) به کمینه خود (۰.۲۹) میرسد. اما با پیچیدهتر شدن درخت (۱۱ تقسیم)، خطا مجدداً افزایش یافته (۰.۳۱) است. این الگوی U شکل در خطا، نشاندهنده وقوع Overfitting در مدل کامل است.
2.7 استراتژی هرس کردن درخت (Pruning Strategy)
برای مقابله با بیشبرازش و رسیدن به یک مدل تعمیمپذیر، باید مفاهیم زیر را در نظر بگیریم:
[Image of overfitting underfitting optimal model diagram]
2.7.1 ۱. مفهوم بیشبرازش و پارامتر پیچیدگی (CP)
یادگیری بیش از حد زمانی رخ میدهد که مدل، نویز
(Noise) موجود در دادههای آموزشی را به جای سیگنال
(Signal) واقعی یاد میگیرد. پارامتر CP مکانیزمی
برای جریمه کردن پیچیدگی مدل است؛ هرچه CP کمتر باشد، درخت اجازه دارد شاخ
و برگ بیشتری داشته باشد و مستعد Overfitting شود.
2.7.2 ۲. تحلیل جدول CP و انتخاب بهترین مدل
ما برای انتخاب نقطه برش بهینه، به ستون xerror (خطای
تخمین زده شده روی دادههای دیده نشده) نگاه میکنیم.
روش حداقل خطا (Min Error): کمترین میزان خطا برابر ۰.۵۰۰۰۰ است که در ردیف ۳ (با
nsplit = 2) رخ داده است.قانون یک خطای استاندارد (1-SE Rule): این یک رویکرد محافظهکارانه است که میگوید: «سادهترین مدلی را انتخاب کن که خطای آن تفاوت معناداری با بهترین مدل نداشته باشد.»
محاسبات:-
کمترین خطا (Best Error):
0.50000 -
خطای استاندارد (SE):
0.07599 -
آستانه مجاز: \(0.50000 + 0.07599 = 0.57599\)
نتیجهگیری: مدل ردیف ۲ دارای خطای
0.59211است که از آستانه مجاز (۰.۵۷۵۹۹) بیشتر است. بنابراین، ما همان ردیف ۳ را به عنوان بهینهترین مدل انتخاب میکنیم.-
2.8 هرس کردن مدل (Pruning)
# مدل هرس شده با cp بهینه
best_cp <- model$cptable[which.min(model$cptable[,"xerror"]), "CP"]
pruned_model <- prune(model, cp = best_cp)
rpart.plot(pruned_model)
ساختار نهایی درخت تصمیم (Pruned Tree Structure):
فرآیند هرس کردن (Pruning) منجر به ایجاد مدلی بسیار شفاف و “تفسیرپذیر”
شد. نکته قابل توجه این است که از بین تمام متغیرها، تنها دو متغیر
yrs.since.phd و yrs.service برای تعیین رتبه
علمی کافی شناخته شدند.
قوانین استخراج شده (Decision Rules):
-
۱. گره ریشه (Root Node): معیار اصلی تصمیمگیری، سابقه
دکترا است.
سوال: آیاyrs.since.phd < 12است؟- خیر (سابقه ≥ ۱۲ سال): فرد مستقیماً به عنوان Prof (استاد تمام) طبقهبندی میشود. (پوشش اکثریت دادهها)
- بله (سابقه < ۱۲ سال): نیاز به بررسی شرط دوم است.
-
۲. گره فرزند (Child Node): برای افراد با سابقه دکترای
کم، سابقه خدمت بررسی میشود.
سوال: آیاyrs.service >= 6است؟- بله: فرد به عنوان AssocProf (دانشیار) طبقهبندی میشود.
- خیر: فرد به عنوان AsstProf (استادیار) طبقهبندی میشود.
3 ارزیابی مدل
اکنون مدل هرس شده و نهایی خود را بر روی دادههای تست (که مدل هرگز ندیده) ارزیابی میکنیم.
baraz <- predict(pruned_model, test, type = "class")
cm <- confusionMatrix(data = baraz, reference = test$rank)
print(cm)## Confusion Matrix and Statistics
##
## Reference
## Prediction AssocProf AsstProf Prof
## AssocProf 4 0 0
## AsstProf 2 15 0
## Prof 9 0 60
##
## Overall Statistics
##
## Accuracy : 0.8778
## 95% CI : (0.7918, 0.9374)
## No Information Rate : 0.6667
## P-Value [Acc > NIR] : 3.922e-06
##
## Kappa : 0.7284
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: AssocProf Class: AsstProf Class: Prof
## Sensitivity 0.26667 1.0000 1.0000
## Specificity 1.00000 0.9733 0.7000
## Pos Pred Value 1.00000 0.8824 0.8696
## Neg Pred Value 0.87209 1.0000 1.0000
## Prevalence 0.16667 0.1667 0.6667
## Detection Rate 0.04444 0.1667 0.6667
## Detection Prevalence 0.04444 0.1889 0.7667
## Balanced Accuracy 0.63333 0.9867 0.8500
ارزیابی عملکرد مدل بر اساس ماتریس آشفتگی (Confusion
Matrix):
این ماتریس نقشه دقیقی از پیشبینیهای درست و نادرست
مدل را ارائه میدهد. نتایج حاصله به شرح زیر است:
- دقت کلی (Overall Accuracy): مدل توانست با دقت ۸۷.۸٪ و شاخص کاپای (Kappa) ۰.۷۲۸ عمل کند که نشاندهنده عملکردی بسیار فراتر از حدس تصادفی است.
-
نقاط قوت (Strengths): مدل در شناسایی کلاسهای
AsstProf(استادیار) وProf(استاد تمام) عملکرد بینظیری داشت و به حساسیت (Sensitivity) ۱۰۰٪ دست یافت. -
نقاط ضعف (Weaknesses): پاشنه آشیل مدل، تشخیص کلاس
AssocProf(دانشیار) است. حساسیت در این کلاس تنها ۲۶.۷٪ بود؛ به طوری که ۹ نفر از ۱۵ دانشیار، به اشتباه به عنوان استاد تمام پیشبینی شدند.
3.1 تحلیل تکمیلی: منحنی ROC و شاخص AUC
در مسائل طبقهبندی چندکلاسه (Multi-class Classification)، برای محاسبه سطح زیر منحنی (AUC)، از رویکرد “یکی در برابر همه” (One-vs-All / OvA) استفاده میشود.
اگرچه پکیج caret در خروجی استاندارد خود مقادیر AUC
چندکلاسه را گزارش نمیکند، اما با توجه به حساسیت (Sensitivity) و ویژگی
(Specificity) بسیار بالا در کلاسهای Prof و
AsstProf، میتوان با اطمینان بالا استنباط کرد که:
- شاخص AUC برای کلاسهای
ProfوAsstProfبسیار بالا (احتمالاً > ۰.۹۰) است. - شاخص AUC برای کلاس
AssocProfبه دلیل خطای تشخیص بالا، متوسط (احتمالاً حدود ۰.۷۹) خواهد بود.
3.2 تحلیل اهمیت متغیرها
## yrs.since.phd yrs.service salary
## 76.53850 58.76535 35.06974
sorted_importance <- sort(importance)
par(mar = c(5, 7, 4, 2) + 0.1)
barplot(
sorted_importance,
main = "اهمیت متغیرها در مدل CART (هرسشده)",
xlab = "اهمیت (Importance)",
horiz = TRUE,
las = 1,
col = "darkred"
)
تفسیر کمی اهمیت متغیرها در درخت تصمیم نهایی:
این
نمودار سهم هر متغیر را در فرآیند تصمیمگیری درخت (بر اساس میزان کاهش
ناخالصی گرهها) به صورت عددی نشان میدهد:
-
متغیرهای غالب (Dominant Predictors):
متغیرyrs.since.phd(سالهای پس از دکترا) با امتیاز قاطع ۷۶.۵، قویترین عامل در پیشبینی رتبه است. پس از آنyrs.service(سابقه خدمت) با امتیاز ۵۸.۸ در رتبه دوم قرار دارد. -
تطابق و اعتبار مدل:
این نتایج کاملاً ساختار نهایی مدل هرسشده را تأیید میکند، زیرا مدل نهایی فقط از همین دو متغیر برای ایجاد تمام قوانین تقسیمبندی استفاده کرده است. -
نقش متغیر حقوق (Salary):
متغیرsalaryبا امتیاز ۳۵.۱، اهمیت نسبی کمتری را نشان داد. این امتیاز حاکی از آن است که حقوق در مدل پیچیدهتر و هرسنشده حضور داشته، اما برای تعیین قوانین نهایی به اندازه متغیرهای سابقه، کلیدی نبوده است. -
متغیرهای کماهمیت:
متغیرهایdisciplineوsexبه دلیل اهمیت ناچیز، در هیچ یک از قوانین تقسیمبندی مدل نهایی استفاده نشدند.
4 مقایسه با مدل جنگل تصادفی
set.seed(38712)
rf_model <- randomForest(
rank ~ .,
data = train,
ntree = 200,
importance = TRUE
)
print(rf_model)##
## Call:
## randomForest(formula = rank ~ ., data = train, ntree = 200, importance = TRUE)
## Type of random forest: classification
## Number of trees: 200
## No. of variables tried at each split: 2
##
## OOB estimate of error rate: 9.09%
## Confusion matrix:
## AssocProf AsstProf Prof class.error
## AssocProf 29 2 16 0.38297872
## AsstProf 3 43 0 0.06521739
## Prof 4 0 178 0.02197802
rf_predictions <- predict(rf_model, test, type = "class")
cm_rf <- confusionMatrix(data = rf_predictions, reference = test$rank)
print(cm_rf)## Confusion Matrix and Statistics
##
## Reference
## Prediction AssocProf AsstProf Prof
## AssocProf 6 0 0
## AsstProf 0 15 0
## Prof 9 0 60
##
## Overall Statistics
##
## Accuracy : 0.9
## 95% CI : (0.8186, 0.9532)
## No Information Rate : 0.6667
## P-Value [Acc > NIR] : 2.485e-07
##
## Kappa : 0.7778
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: AssocProf Class: AsstProf Class: Prof
## Sensitivity 0.40000 1.0000 1.0000
## Specificity 1.00000 1.0000 0.7000
## Pos Pred Value 1.00000 1.0000 0.8696
## Neg Pred Value 0.89286 1.0000 1.0000
## Prevalence 0.16667 0.1667 0.6667
## Detection Rate 0.06667 0.1667 0.6667
## Detection Prevalence 0.06667 0.1667 0.7667
## Balanced Accuracy 0.70000 1.0000 0.8500
accuracy_cart <- cm$overall["Accuracy"]
accuracy_rf <- cm_rf$overall["Accuracy"]
print(paste("دقت مدل درخت تصمیم (CART):", round(accuracy_cart, 4)))## [1] "دقت مدل درخت تصمیم (CART): 0.8778"
## [1] "دقت مدل جنگل تصادفی (RF): 0.9"
تحلیل تطبیقی: درخت تصمیم (CART) در برابر جنگل تصادفی (Random
Forest):
مدل Random Forest به عنوان یک روش
Ensemble (گروهی) که از تجمیع آراء صدها درخت تصمیم
استفاده میکند، تفاوتهای عملکردی زیر را با مدل تکدرختی نشان داد:
-
مزایای Random Forest:
- کاهش Overfitting از طریق میانگینگیری پیشبینیهای چندین درخت.
- مقاومت بالاتر در برابر نویز و دادههای پرت.
- دقت پیشبینی بالاتر (افزایش دقت از ۸۷.۸٪ به ۹۰٪ در این تحلیل).
-
مزایای CART (درخت تصمیم ساده):
- تفسیرپذیری کامل (Interpretability): قوانین به صورت “اگر-آنگاه” کاملاً شفاف هستند.
- سرعت آموزش و پیشبینی بسیار بالا.
- مناسب برای ارائه به ذینفعان غیرفنی.
نکته: نمودار اهمیت متغیرها در هر دو مدل یکسان بود و
yrs.since.phd و yrs.service را به عنوان عوامل
اصلی شناسایی کرد که اعتبار تحلیل را تایید میکند.
5 نتیجهگیری و پیشنهادات
خلاصه یافتههای کلیدی:
-
عوامل تعیینکننده: متغیرهای سابقه دکترا
(
yrs.since.phd) و سابقه خدمت (yrs.service) قویترین پیشبینیکنندههای رتبه آکادمیک هستند. متغیرهای جنسیت و رشته تأثیر معناداری نداشتند. -
ارزیابی عملکرد: مدل درخت تصمیم هرسشده با دقت
۸۷.۸٪ عملکرد قابل قبولی دارد. با این حال، پاشنه آشیل
مدل، تشخیص کلاس
AssocProf(دانشیار) است که اغلب با استاد تمام اشتباه گرفته میشود. - شفافیت مدل: مدل نهایی به طرز شگفتانگیزی ساده شد و تنها با ۲ قانون تصمیمگیری توانست اکثریت دادهها را به درستی طبقهبندی کند.
مسیرهای بهبود در آینده (Future Work):
- جمعآوری دادههای بیشتر (Over-sampling) برای کلاس AssocProf جهت رفع عدم توازن.
- مهندسی ویژگی (Feature Engineering): افزودن ستونهایی مانند “تعداد مقالات”، “h-index” یا “گرنتهای دریافتی” برای تمایز بهتر بین رتبههای علمی.
- استفاده از روشهای Boosting (مانند XGBoost) اگر اولویت با دقت مدل است و تفسیرپذیری اهمیت کمتری دارد.
5.0.1 چند نکته فراتر
theme_set(theme_minimal())
p_rank <- ggplot(mis, aes(x = rank, fill = rank)) +
geom_bar() +
labs(title = "توزیع رتبه (Rank)")
p_disc <- ggplot(mis, aes(x = discipline, fill = discipline)) +
geom_bar() +
labs(title = "توزیع رشته (Discipline)")
p_sex <- ggplot(mis, aes(x = sex, fill = sex)) +
geom_bar() +
labs(title = "توزیع جنسیت (Sex)")
(p_rank | p_disc | p_sex)p_phd_hist <- ggplot(mis, aes(x = yrs.since.phd)) +
geom_histogram(bins = 20, fill = "skyblue", color = "black") +
labs(title = "توزیع سالهای پس از دکترا", x = "Yrs. Since PhD")
p_serv_hist <- ggplot(mis, aes(x = yrs.service)) +
geom_histogram(bins = 20, fill = "salmon", color = "black") +
labs(title = "توزیع سابقه خدمت", x = "Yrs. Service")
p_sal_hist <- ggplot(mis, aes(x = salary)) +
geom_histogram(bins = 30, fill = "lightgreen", color = "black") +
labs(title = "توزیع حقوق", x = "Salary")
(p_phd_hist | p_serv_hist) / (p_sal_hist)p_phd_box <- ggplot(mis, aes(y = yrs.since.phd)) +
geom_boxplot(fill = "skyblue") +
labs(title = "باکس پلات سالهای پس از دکترا") +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
p_serv_box <- ggplot(mis, aes(y = yrs.service)) +
geom_boxplot(fill = "salmon") +
labs(title = "باکس پلات سابقه خدمت") +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
p_sal_box <- ggplot(mis, aes(y = salary)) +
geom_boxplot(fill = "lightgreen") +
labs(title = "باکس پلات حقوق") +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())
(p_phd_box | p_serv_box | p_sal_box)p_rank_sal_box <- ggplot(mis, aes(x = rank, y = salary, fill = rank)) +
geom_boxplot() +
labs(title = "رابطه حقوق و رتبه (Salary by Rank)", x = "Rank", y = "Salary") +
theme(legend.position = "none")
print(p_rank_sal_box)rf_imp <- as.data.frame(importance(rf_model))
rf_imp$Variable <- rownames(rf_imp)
ggplot(rf_imp, aes(x = MeanDecreaseGini, y = fct_reorder(Variable, MeanDecreaseGini))) +
geom_col(fill = "steelblue") +
labs(
title = "اهمیت متغیرها در مدل (Random Forest)",
x = "اهمیت (MeanDecreaseGini)",
y = "متغیر"
) +
theme_minimal()par(mfrow = c(1, 2), mar = c(5, 4, 4, 2) + 0.1)
boxplot(yrs.since.phd ~ rank,
data = mis,
main = "سابقه دکترا بر اساس رتبه",
xlab = "رتبه (Rank)",
ylab = "سالهای پس از دکترا",
col = c("#0a9396", "#ee9b00", "#005f73"))
boxplot(yrs.service ~ rank,
data = mis,
main = "سابقه خدمت بر اساس رتبه",
xlab = "رتبه (Rank)",
ylab = "سالهای خدمت",
col = c("#0a9396", "#ee9b00", "#005f73"))5.0.2 نتیجهگیری نهایی
خلاصه مدیریتی و دستاوردهای تحلیل:
در این پروژه، مدلی موفق برای پیشبینی رتبه اعضای هیئت علمی توسعه یافت. نتایج به شرح زیر است:
-
۱. کشف الگوهای پنهان: تحلیلها اثبات کرد که متغیرهای
زمانی، بهویژه
yrs.since.phd(سالهای پس از دکترا) وyrs.service(سابقه خدمت)، قویترین پیشبینیکنندهها هستند. در مقابل، متغیرهای دموگرافیک مانند رشته (Discipline) و جنسیت (Sex) تأثیر ناچیزی در تعیین رتبه داشتند. -
۲. تعادل بین دقت و تفسیرپذیری:
- مدل درخت تصمیم (CART): با وجود سادگی فوقالعاده (تنها ۲ قانون)، به دقت قابل قبول ۸۷.۸٪ دست یافت که برای تصمیمگیریهای شفاف مدیریتی ایدهآل است.
- مدل جنگل تصادفی (Random Forest): با پیچیدگی بیشتر، دقت را به ۹۰.۰٪ ارتقا داد که اعتبار متغیرهای انتخابی را تایید میکند.
- ۳. چالش اصلی (The Bottleneck): پاشنه آشیل هر دو مدل، تشخیص رتبه «دانشیار» (AssocProf) بود. مدل CART تنها ۲۶.۷٪ و مدل RF حدود ۴۰٪ از دانشیاران را درست تشخیص دادند. این نشان میدهد که مرز بین “دانشیار” و “استاد تمام” صرفاً با سنوات خدمت قابل تفکیک نیست.
پیشنهاد استراتژیک:
برای بهبود مدل در فازهای بعدی، پیشنهاد میشود علاوه بر جمعآوری دادههای بیشتر برای کلاس دانشیار، از شاخصهای عملکردی (مانند تعداد مقالات، شاخص h-index و حجم گرنتهای پژوهشی) به عنوان متغیرهای ورودی استفاده شود.